import pandas
from os.path import splitext


class Big_Data_Option:
    """
    一个用于处理大数据文件的类
    """

    def __init__(self):
        self.data_handle = pandas.DataFrame()

    # 分析文件路径的后缀名
    def _analyze_suffix(self, file_path):
        """
        分析文件路径的后缀名

        参数:
        file_path (str): 文件的路径

        返回:
        str: 文件的后缀名（小写）
        """
        file_suffix = splitext(file_path)[1][1:]  # 获取后缀名并去除点
        return file_suffix.lower()  # 转换为小写返回

    # 打开文件
    def open_file(self, file_path, sheet_name=None):
        """
        根据文件后缀名打开文件并获取相应的 DataFrame

        参数:
        file_path (str): 文件的路径
        sheet_name (str, 可选): 对于 Excel 文件，指定要读取的工作表名称

        返回:
        pandas.DataFrame: 读取文件得到的 DataFrame 或 None（如果文件格式不支持）
        """
        suffix = self._analyze_suffix(file_path)
        try:
            if suffix in ["xlsx", "xls"]:
                self.data_handle = pandas.read_excel(file_path, sheet_name=sheet_name)
            elif suffix in ["csv"]:
                self.data_handle = pandas.read_csv(file_path)
            else:
                print(f"不支持的文件格式: {suffix}")
                return None
            return self.data_handle
        except Exception as e:
            print(f"读取文件时发生错误: {e}")
            return None

    # 保存文件
    def save_file(self, output_file_path):
        suffix = self._analyze_suffix(output_file_path)
        try:
            if suffix in ["csv"]:
                self.data_handle.to_csv(output_file_path, index=False)
            elif suffix in ["xlsx", "xls"]:
                self.data_handle.to_excel(output_file_path, index=False)
            else:
                print(f"不支持的保存文件格式: {suffix}")
        except Exception as e:
            print(f"保存文件时发生错误: {e}")

    # 列表转dataframe
    def list_to_dataframe(self, data_list):
        """
        将输入的列表转换为 DataFrame

        参数:
        data_list (list of dict): 包含数据的列表，其中每个元素是一个字典
        [
        {"序号": 1,"年级": "四年级","班级": 5,"学生姓名": "王五"},
        {"序号": 1,"年级": "四年级","班级": 5,"学生姓名": "张三",}
        ]

        返回:
        pandas.DataFrame: 转换后的 DataFrame
        """
        self.data_handle = pandas.DataFrame(data_list)
        return pandas.DataFrame(data_list)

    # dataframe转列表
    def dataframe_to_list(self, data_frame, mode: int = 0):
        """
        将输入的 DataFrame 转换为指定格式的列表

        参数:
        data_frame (pandas.DataFrame): 要转换的 DataFrame
        mode:模式，默认为0，返回[{},{}]格式；模式其他，返回[[],[],]格式

        返回:
        list: 转换后的列表，格式为 [{"属性名": "属性值",...}, {...},...]
        """
        if mode == 0:
            result = []
            for index, row in data_frame.iterrows():
                item = {}
                for column in data_frame.columns:
                    item[column] = row[column]
                result.append(item)
            return result
        else:
            return data_frame.values.tolist()

    # 重置索引
    def reset_index(self):
        """
        重置 DataFrame 的索引

        返回:
        pandas.DataFrame: 索引已重置的 DataFrame
        """
        self.data_handle = self.data_handle.reset_index(drop=True)
        return self.data_handle

    # 删除指定行
    def delete_specific_rows(self, row_indices):
        """
        删除指定行

        参数:
        row_indices (list): 要删除的行的索引列表

        返回:
        pandas.DataFrame: 删除指定行后的 DataFrame
        """
        try:
            self.data_handle = self.data_handle.drop(row_indices)
            return self.data_handle
        except Exception as e:
            print(f"删除指定行时发生错误: {e}")
            return None

    # 删除指定列
    def delete_specific_columns(self, column_names):
        """
        删除指定列

        参数:
        column_names (list): 要删除的列的名称列表

        返回:
        pandas.DataFrame: 删除指定列后的 DataFrame
        """
        try:
            self.data_handle = self.data_handle.drop(column_names, axis=1)
            return self.data_handle
        except Exception as e:
            print(f"删除指定列时发生错误: {e}")
            return None

    # 获取表头
    def get_column_names(self):
        """
        获取 DataFrame 的表头

        返回:
        list: 表头的列名列表
        """
        try:
            return self.data_handle.columns.tolist()
        except Exception as e:
            print(f"获取表头时发生错误: {e}")
            return None

    # 查看指定行数据
    def view_specific_row(self, row_index: int):
        """
        查看指定行数据，并以字典形式返回

        参数:
        row_index (int): 要查看的行的索引

        返回:
        dict: 包含指定行数据的字典，键为列名，值为对应的数据
        """
        try:
            return dict(self.data_handle.iloc[row_index])
        except Exception as e:
            print(f"查看指定行数据时发生错误: {e}")
            return None

    # 查看指定字典筛选的数据
    def view_filtered_data(self, filter_dict):
        """
        根据指定字典筛选数据，并以字典形式返回

        参数:
        filter_dict (dict): 包含筛选条件的字典，键为列名，值为筛选值

        返回:
        dict: 筛选后的数据组成的字典
        """
        try:
            filtered_df = self.data_handle[
                self.data_handle[list(filter_dict.keys())].isin(list(filter_dict.values())).all(axis=1)]
            return filtered_df.to_dict('records')
        except Exception as e:
            print(f"筛选数据时发生错误: {e}")
            return None

    # 查看指定列数据
    def view_specific_column(self, column_name, is_tolist=False):
        """
        查看指定列数据

        参数:
        column_name (str): 要查看的列名

        返回:

        如果只查看单列，返回list: 指定列的数据组成的列表
        否则返回dataframe
        """
        try:
            if is_tolist:
                return self.data_handle[column_name].tolist()
            else:
                return self.data_handle[column_name]
        except Exception as e:
            print(f"查看指定列数据时发生错误: {e}")
            return None

    # 查看指定的单元格值
    def view_specific_cell(self, row_index, column_name):
        """
        查看指定的单元格值

        参数:
        row_index (int): 行索引
        column_name (str): 列名

        返回:
        单元格的值，如果出现错误则返回 None
        """
        try:
            return self.data_handle.at[row_index, column_name]
        except Exception as e:
            print(f"查看指定单元格值时发生错误: {e}")
            return None

    # 修改指定的单元格值
    def modify_specific_cell(self, row_index, column_name, new_value):
        """
        修改指定的单元格值

        参数:
        row_index (int): 行索引
        column_name (str): 列名
        new_value: 新的值

        返回:
        bool: 修改是否成功
        """
        try:
            self.data_handle.at[row_index, column_name] = new_value
            return True
        except Exception as e:
            print(f"修改指定单元格值时发生错误: {e}")
            return False

    # 获取 DataFrame 的行数
    def get_row_count(self):
        """
        获取 DataFrame 的行数

        返回:
        int: 行数
        """
        try:
            return self.data_handle.shape[0]
        except Exception as e:
            print(f"获取行数时发生错误: {e}")
            return None

    # 获取 DataFrame 的列数
    def get_column_count(self):
        """
        获取 DataFrame 的列数

        返回:
        int: 列数
        """
        try:
            return self.data_handle.shape[1]
        except Exception as e:
            print(f"获取列数时发生错误: {e}")
            return None

    # 指定列、操作符和值进行筛选
    def data_filtering(self, column_name, operator, value):
        """
        通用的数据筛选方法，根据指定列、操作符和值进行筛选

        参数:
        column_name (str): 要筛选的列名
        operator (str): 操作符，如 '>', '<', '>=', '<=', '=='
        value: 用于比较的值

        返回:
        pandas.DataFrame: 筛选后的结果
        """
        try:
            if operator == '>':
                return self.data_handle[self.data_handle[column_name] > value]
            elif operator == '<':
                return self.data_handle[self.data_handle[column_name] < value]
            elif operator == '>=':
                return self.data_handle[self.data_handle[column_name] >= value]
            elif operator == '<=':
                return self.data_handle[self.data_handle[column_name] <= value]
            elif operator == '==':
                return self.data_handle[self.data_handle[column_name] == value]
            else:
                print("不支持的操作符")
                return None
        except Exception as e:
            print(f"数据筛选时发生错误: {e}")
            return None

    # 数据排序
    def data_sorting(self, column_name, ascending: bool = True):
        """
        对数据进行排序

        参数:
        column_name (str): 用于排序的列名
        ascending (bool, 可选): 排序顺序，默认为升序（True）。如果为 False，则为降序

        返回:
        pandas.DataFrame: 排序后的结果
        """
        try:
            self.data_handle = self.data_handle.sort_values(by=column_name, ascending=ascending)
            # return self.data_handle.sort_values(by=column_name, ascending=ascending)
            return True
        except Exception as e:
            print(f"数据排序时发生错误: {e}")
            return None

    # 数据去重
    def data_deduplication(self):
        """
        对数据进行去重

        返回:
        pandas.DataFrame: 去重后的结果
        """
        try:
            self.data_handle = self.data_handle.drop_duplicates()
            return True
        except Exception as e:
            print(f"数据去重时发生错误: {e}")
            return False

    # 重命名列名
    def rename_columns(self, old_names, new_names):
        """
        重命名列名

        参数:
        old_names (list): 旧列名列表
        new_names (list): 新列名列表

        返回:
        pandas.DataFrame: 重命名后的 DataFrame
        """
        try:
            self.data_handle.rename(columns=dict(zip(old_names, new_names)), inplace=True)
            return self.data_handle
        except Exception as e:
            print(f"重命名列名时发生错误: {e}")
            return None

    # 显示指定列的数据类型
    def show_column_dtype(self, column_name):
        """
        显示指定列的数据类型

        参数:
        column_name (str): 要显示数据类型的列名

        返回:
        str: 数据类型
        """
        try:
            return self.data_handle[column_name].dtype
        except Exception as e:
            print(f"显示指定列数据类型时发生错误: {e}")
            return None

    # 显示指定单元格的数据类型
    def show_cell_dtype(self, row_index, column_name):
        """
        显示指定单元格的数据类型

        参数:
        row_index (int): 行索引
        column_name (str): 列名

        返回:
        str: 数据类型
        """
        try:
            return self.data_handle.at[row_index, column_name].dtype
        except Exception as e:
            print(f"显示指定单元格数据类型时发生错误: {e}")
            return None

    # 修改指定列的数据类型
    def modify_column_dtype(self, column_name, new_dtype):
        """
        修改指定列的数据类型

        参数:
        column_name (str): 要修改数据类型的列名
        new_dtype: 新的数据类型，例如 'int', 'float', 'str', 'bool', 'datetime' 等

        返回:
        bool: 修改是否成功
        """
        try:
            self.data_handle[column_name] = self.data_handle[column_name].astype(new_dtype)
            return True
        except Exception as e:
            print(f"修改指定列数据类型时发生错误: {e}")
            return False

    # 合并两个 DataFrame
    def merge_dataframes(self, df1, df2):
        try:
            return pandas.concat([df1, df2])
        except Exception as e:
            print(f"合并 DataFrame 时发生错误: {e}")
            return None

    # 将nan值替换为指定的值
    def replace_nan_with_value(self, replace_value):
        """
        将DataFrame中的nan值替换为指定的值

        参数:
        replace_value: 用于替换nan的值

        返回:
        pandas.DataFrame: 替换后的DataFrame
        """
        try:
            self.data_handle = self.data_handle.fillna(replace_value)
            return self.data_handle
        except Exception as e:
            print(f"替换nan值时发生错误: {e}")
            return None

    # 新增：列出指定表头列表的dataframe
    def list_dataframe_with_columns(self, column_list):
        """
        列出指定表头列表的dataframe

        参数:
        column_list (list): 需要包含的列名列表

        返回:
        pandas.DataFrame: 包含指定列的DataFrame，如果列不存在则包含可能的列
        """
        # 获取当前DataFrame的列名
        current_columns = self.data_handle.columns.tolist()

        # 检查指定的列是否都存在
        available_columns = [col for col in column_list if col in current_columns]

        # 如果没有找到任何匹配的列，返回空DataFrame
        if not available_columns:
            print("警告: 指定的列均不存在于当前DataFrame中")
            return pandas.DataFrame()

        # 如果有列不存在，给出警告
        missing_columns = [col for col in column_list if col not in current_columns]
        if missing_columns:
            print(f"警告: 列 {missing_columns} 不存在于当前DataFrame中，已忽略")

        # 返回包含可用列的DataFrame
        self.data_handle = self.data_handle[available_columns]
        return self.data_handle[available_columns]
